﻿//Copyright 2011 University of Southampton 
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Diagnostics;
using SharePointEntityProject.Properties;

namespace EntityEditorLib
{
    public class AllowUnsafeUpdates:IDisposable
    {

        private readonly SPWeb _Web;
        public AllowUnsafeUpdates(SPWeb web)
        {
            _Web = web;
            //The Microsoft idea behind introducing the AllowUnsafeUpdates property is to protect YOU from 
            //cross-site scripting attacks. The way this works is that if your application is running in an 
            //HTTPContext (i.e. it’s a web part for instance) and the request is a GET request then SharePoint 
            //will refuse to do any changes unless the value of AllowUnsafeUpdates is set to true and by
            //default it will be false for GET requests. If you try to do any updates to lists, webs or any 
            //SharePoint objects that require an SPSite to be created first, and if you don’t set 
            //AllowUnsafeUpdates to true you will get an exception:
            _Web.AllowUnsafeUpdates = true;
            _Web.Update();
        }



        public void Dispose()
        {
            _Web.AllowUnsafeUpdates = false;
            _Web.Update();
        }
    }

    /// <summary>
    /// Settings required for creating a new list.
    /// </summary>
    public class ListSettings
    {
        private SPSite site;
        private SPWeb web;
        public ListSettings(SPSite site, SPWeb web)
        {
            this.site = site;
            this.web = web;
        }

        public string title;
        public string description;

        public SPListTemplate template
        {
            get
            {
                return web.ListTemplates[templateStr];
            }
        }
        public string templateStr;
        public List<SPContentType> ctCollection
        {
            //Lookup all CT by name, ignore if does not exits
            get
            {

                List<SPContentType> ctCollection = new List<SPContentType>();
                try
                {
                    string[] ct = contentTypesStr.Split(';');

                    foreach (string c in ct)
                    {
                        //get the ct
                        SPContentType curCT = web.ContentTypes[c.Trim()];
                        //add to col
                        if (curCT == null)
                        {
                            Debug.WriteLine("WARNING: Attempted to use an invalid content type named : " + c);
                        }
                        else
                        {
                            ctCollection.Add(curCT);
                        }

                    }
                }
                catch (NullReferenceException ex)
                {
                    //Null is valid - ignore
                    return ctCollection;
                }
                return ctCollection;
            }
        }
        public string contentTypesStr;
        public bool isOnQuickLaunch;
        public bool isAllowContentTypes;
        public bool isEnableFolderCreation;
        public bool isEnableVersioning;

    }

    /// <summary>
    /// Higher level class to manage lists.
    /// </summary>
    public class ListManagementLib:IDisposable
    {
        private string SITE_URL;
        private SPSite site;
        private SPWeb web;

        public ListManagementLib(string SITE_URL)
        {
            this.SITE_URL = SITE_URL;
            this.site = new SPSite(this.SITE_URL);//Dispose
            this.web = site.OpenWeb();//Dispose

          

        }

        
        /// <summary>
        /// Disposes of all SP objects that were used. 
        /// </summary>
        public void Dispose()
        {

            //If this method is NOT called expect this error in the ULS
            //-  - Unhandled exception was thrown by the sandboxed code wrapper's Execute method 
            //in the partial trust app domain: An unexpected error has occurred.

            web.AllowUnsafeUpdates = false;//Be aware of attack, set to false where possible.
            web.Update();
            this.web.Dispose();
            this.site.Dispose();
        }

        /// <summary>
        /// Get the settings already associated with a list
        /// </summary>
        /// <param name="listName"></param>
        /// <returns></returns>
        public ListSettings GetListSettings(string listName)
        {

            ListSettings settings = new ListSettings(site, web);//Create a blank settings object
            try
            {
                SPList list = this.GetListByName(listName);
                //TODO: Populate list settings here!
                settings.title = list.Title;
                settings.description = list.Description;
                settings.isOnQuickLaunch = list.OnQuickLaunch;
                settings.isAllowContentTypes = list.AllowContentTypes;

                settings.isEnableFolderCreation = list.EnableFolderCreation;
                settings.isEnableVersioning = list.EnableVersioning;

            }
            catch (Exception ex)
            {
                Debug.WriteLine("List does not exist");
            }

            return settings;


        }

        public SPContentTypeCollection GetAllCTForList(string name)
        {
           SPList curList = 
               this.GetListByName(name);

           return curList.ContentTypes;
        }



        private static void AddContentTypeToList(List<SPContentType> contentTypeList, SPList curList)
        {
            //TODO: remove CT that are in list but not in this list? (i.e. remove)
            foreach (SPContentType curCt in contentTypeList )
            {
                //CT is already a valid one

                //Look to see if it is already added
                SPContentType ctExists = curList.ContentTypes[curCt.Name];
                if (ctExists == null)
                {
                    //ADD
                    curList.ContentTypes.Add(curCt);
                    Debug.WriteLine(String.Format("Added content type:  {0} to list: {1}", curCt.Name, curList.Title));
                }
                else
                {

                    Debug.WriteLine(String.Format("Content type :  {0} already added to  list: {1}", curCt.Name, curList.Title));
                }


            }
        }



        private SPList GetListByName(string listName)
        {
            ListSettings settings = new ListSettings(site, web);
            settings.title = listName;
            return this.GetListByName(settings);

        }

        private SPList GetListByName(ListSettings settings)
        {
            SPList curList;
            try
            {
                curList = web.Lists[settings.title];
                Debug.WriteLine(String.Format("Create a list that exists? : {0}", curList.Title));
            }
            catch (ArgumentException ex)
            {
                Debug.WriteLine(ex.Message.ToString());
                //create
                if (settings.description == null)
                {
                    settings.description = Resources.DefaultListDescriptionText;
                }

                if (settings.templateStr == null)
                {
                    settings.templateStr = Resources.DefaultListTemplate;
                }
                try
                {
                    web.Lists.Add(settings.title, settings.description, settings.template);
                    web.Update();
                }
                catch
                {
                    throw new Exceptions.InvalidWebpartValue(Resources.WebpartIncorrectlyConfiguredStr);
                }
                curList = web.Lists[settings.title];

                curList.Update(true);
                Debug.WriteLine(String.Format("Created CT : {0}", settings.title));
            }
            return curList;
        }
        /// <summary>
        /// Creates a new list based on the settings. If the list exists (by name) then create is ignored. 
        /// </summary>
        /// <param name="settings">List name i.e. title</param>
        /// <returns>SPList object once created or if already existed </returns>
        public   SPList CreateOrUpdateList(ListSettings settings)
        {
            using (new AllowUnsafeUpdates(web))
            {
             
            //GET or create
            SPList curList = GetListByName(settings);

            //UPDATE description
            if (!curList.Description.Equals(settings.description))
            {
                curList.Description = settings.description;

                curList.Update(true);
                Debug.WriteLine(String.Format("Changed description of list to : {0}", curList.Description));
            }


            //Update ct to are related to this list
            AddContentTypeToList(settings.ctCollection, curList);

            //Update is Visible            
            curList.OnQuickLaunch = settings.isOnQuickLaunch;
            curList.ContentTypesEnabled = settings.isAllowContentTypes;

            curList.EnableFolderCreation = settings.isEnableFolderCreation;
            curList.EnableVersioning = settings.isEnableVersioning;


            
                //Save
                curList.Update(true);
                return curList;
            }

             

        }
    }
}
